//
//  BDSpeechManager.m
//  BDSpeech
//
//  Created by jnl on 2017/12/7.
//  Copyright © 2017年 qin. All rights reserved.
//

#import "BDSpeechManager.h"
#import "GlobalHeader.h"
//识别
#import "BDSASRDefines.h"
#import "BDSASRParameters.h"
#import "BDSWakeupDefines.h"
#import "BDSWakeupParameters.h"
#import "BDSEventManager.h"
#import "BDRecognizerViewController.h"
//#import "AudioInputStream.h"
//合成
#import "BDSSpeechSynthesizer.h"
//#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
//#import "ConfigManager.h"

//#error "请在官网新建应用，配置包名，并在此填写应用的 api key, secret key, appid(即appcode)"
NSString* APP_ID = @"10462905";
NSString* API_KEY = @"uFxsG6WE5ZYd8tuzjqjXSlLn";
NSString* SECRET_KEY = @"3535196d3ecadf41962dac2ad1b5bbbc";


@interface BDSpeechManager ()<AVAudioPlayerDelegate,BDSSpeechSynthesizerDelegate>
{
    int flag;
}
    

@property (nonatomic,strong)BDSEventManager *asrEventManager;
@property (nonatomic,strong)BDSEventManager *wakeupEventManager;
///是否继续识别
@property(nonatomic, assign) BOOL continueToVR;
@property(nonatomic, assign) BOOL isRecogniting;

//0.合成就识别  1.合成就唤醒
@property (nonatomic,assign)int synthesizerType;
@property (nonatomic,strong)NSMutableArray *musicArray;

@end

@implementation BDSpeechManager


+ (id)shareManager {
    static BDSpeechManager *shareManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareManager = [[self alloc] init];
    });
    return shareManager;
}

/*
 * 这个类里面是初始化所有的定义的数据
 * 这个类不需要运用单列模式
 */
-(instancetype)init
{
    if (self=[super init]) {
        self.languageKey=@"普通话";
         [self configSpeech];
        [[AVAudioSession sharedInstance] setActive:YES error:nil];
        [self buildMusicArray];
    }
    return self;
}

-(void)buildMusicArray{
    _musicArray=[NSMutableArray array];
    //没网络
     [_musicArray addObject:[self buildAudioPlayer:@"no_net.wav"]];
    //hello
        [_musicArray addObject:[self buildAudioPlayer:@"hello.wav"]];
    //没家庭
    [_musicArray addObject:[self buildAudioPlayer:@"no_family.wav"]];
    //没房间
    [_musicArray addObject:[self buildAudioPlayer:@"no_room.wav"]];
    //OK
    [_musicArray addObject:[self buildAudioPlayer:@"ok.wav"]];
    //sorry
    [_musicArray addObject:[self buildAudioPlayer:@"sorry.wav"]];
    //没有对应的命令
    [_musicArray addObject:[self buildAudioPlayer:@"no_cmd.wav"]];
}

/**
 * 创建音频播放器
 */
-(AVAudioPlayer *)buildAudioPlayer:(NSString *)name{
NSString *path=[[NSBundle mainBundle] pathForResource:name ofType:nil];
    NSURL *playUrl=[NSURL URLWithString:path];
    NSError *error;
    AVAudioPlayer *currPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:playUrl error:&error];
  currPlayer.volume=1.0;
   currPlayer.delegate=self;
    return currPlayer;
}




#pragma mark - 启动识别
-(void)startRecognition{
    self.synthesizerType=0;
   
    [self startWakeup];
}

#pragma mark - 取消识别
-(void)cancelRecognition{
    [self stopWakeup];
    if (_asrEventManager) {
        [self stopOnlineRecognition];
        _asrEventManager=nil;
    }
    if (_wakeupEventManager) {
         [self stopWakeup];
        _wakeupEventManager=nil;
    }
    [self cancelSynthesizer];
}


/*********************语音识别相关方法***********************/

#pragma mark - 配置语音
- (void)configSpeech {
    
  [self configWakeupSettings];
  [self configRecognition];
//    [self configureSDK];
    
}

#pragma mark - Private: Configuration
- (void)configRecognition {
    
    self.asrEventManager=[BDSEventManager createEventManagerWithName:BDS_ASR_NAME];
   
    //设置DEBUG_LOG的级别
    
//    [self.asrEventManager setParameter:@(EVRDebugLogLevelOff) forKey:BDS_ASR_DEBUG_LOG_LEVEL];
//
    //配置API_KEY 和 SECRET_KEY 和 APP_ID
    [self.asrEventManager setParameter:@[API_KEY, SECRET_KEY] forKey:BDS_ASR_API_SECRET_KEYS];
    [self.asrEventManager setParameter:APP_ID forKey:BDS_ASR_OFFLINE_APP_CODE];
   //设置录音缓存
    [self.asrEventManager setParameter:@(YES) forKey:BDS_ASR_NEED_CACHE_AUDIO];
    // 参数设置：识别策略为离在线并行
    [self.asrEventManager setParameter:@(EVR_STRATEGY_ONLINE) forKey:BDS_ASR_STRATEGY];
    [self.asrEventManager setDelegate:self];
    [self setASRLanguage];
    
    //配置端点检测（二选一）
//     [self configModelVAD];
     [self configDNNMFE];
    //     [self.asrEventManager setParameter:@"15361" forKey:BDS_ASR_PRODUCT_ID];
    // ---- 语义与标点 -----
//    [self enableNLU];
    //    [self enablePunctuation];
    // ------------------------
}

- (void) enableNLU {
    // ---- 开启语义理解 -----
    [self.asrEventManager setParameter:@(YES) forKey:BDS_ASR_ENABLE_NLU];
    [self.asrEventManager setParameter:@"15361" forKey:BDS_ASR_PRODUCT_ID];
}

- (void)configModelVAD {
    NSString *modelVAD_filepath = [[NSBundle mainBundle] pathForResource:@"bds_easr_basic_model" ofType:@"dat"];
    [self.asrEventManager setParameter:modelVAD_filepath forKey:BDS_ASR_MODEL_VAD_DAT_FILE];
    [self.asrEventManager setParameter:@(YES) forKey:BDS_ASR_ENABLE_MODEL_VAD];
}

- (void)configDNNMFE {
    NSString *mfe_dnn_filepath = [[NSBundle mainBundle] pathForResource:@"bds_easr_mfe_dnn" ofType:@"dat"];
    [self.asrEventManager setParameter:mfe_dnn_filepath forKey:BDS_ASR_MFE_DNN_DAT_FILE];
    NSString *cmvn_dnn_filepath = [[NSBundle mainBundle] pathForResource:@"bds_easr_mfe_cmvn" ofType:@"dat"];
    [self.asrEventManager setParameter:cmvn_dnn_filepath forKey:BDS_ASR_MFE_CMVN_DAT_FILE];
}

#pragma mark - 停止唤醒
- (void)stopWakeup
{
    DLog(@"停止唤醒");
    [self.wakeupEventManager sendCommand:BDS_WP_CMD_STOP];
    [self.wakeupEventManager sendCommand:BDS_WP_CMD_UNLOAD_ENGINE];
}

#pragma mark - 开始唤醒
- (void)startWakeup
{
    DLog(@"开始唤醒");
    self.continueToVR=YES;
    [self.wakeupEventManager setParameter:nil forKey:BDS_WAKEUP_AUDIO_FILE_PATH];
    [self.wakeupEventManager setParameter:nil forKey:BDS_WAKEUP_AUDIO_INPUT_STREAM];
    [self.wakeupEventManager sendCommand:BDS_WP_CMD_LOAD_ENGINE];
    [self.wakeupEventManager sendCommand:BDS_WP_CMD_START];
}

#pragma mark - 配置唤醒设置
- (void)configWakeupSettings
{
     self.wakeupEventManager=[BDSEventManager createEventManagerWithName:BDS_WAKEUP_NAME];
    [self.wakeupEventManager setDelegate:self];
    [self.wakeupEventManager setParameter:APP_ID forKey:BDS_WAKEUP_APP_CODE];
    NSString *dat=[[NSBundle mainBundle] pathForResource:@"bds_easr_basic_model" ofType:@"dat"];
    // 默认的唤醒词为"百度一下"，如需自定义唤醒词，请在 http://ai.baidu.com/tech/speech/wake 中评估并下载唤醒词，替换此参数
    //    NSString *words=[[NSBundle mainBundle] pathForResource:@"bds_easr_wakeup_words" ofType:@"dat"];
    NSString *words=[[NSBundle mainBundle] pathForResource:@"WakeUp" ofType:@"bin"];
    [self.wakeupEventManager setParameter:dat forKey:BDS_WAKEUP_DAT_FILE_PATH];
    [self.wakeupEventManager setParameter:words forKey:BDS_WAKEUP_WORDS_FILE_PATH];
    //    [self.wakeupEventManager setParameter:@(EVRDebugLogLevelOff) forKey:BDS_ASR_DEBUG_LOG_LEVEL];
    
}

#pragma mark -停止在线识别
- (void)stopOnlineRecognition{
    DLog(@"停止在线识别");
    [self.asrEventManager sendCommand:BDS_ASR_CMD_STOP];
}

#pragma mark - 开启在线识别
- (void)startOnlineRecognition{
     DLog(@"开启在线识别");
    [self.asrEventManager setParameter:nil forKey:BDS_ASR_AUDIO_FILE_PATH];
    [self setASRLanguage];
    [self.asrEventManager sendCommand:BDS_ASR_CMD_START];
        _isRecogniting=YES;
}


#pragma mark - 设置识别语言
-(void)setASRLanguage
{
//     NSString *languageKey=[StorageUtil getLanguageKey];
     NSString *languageKey=@"普通话";
    if([languageKey isEqualToString:self.languageKey]){
        return;
    }
    if ([languageKey isEqualToString:@"普通话"]) {
         [self.asrEventManager setParameter:@(EVoiceRecognitionLanguageChinese) forKey:BDS_ASR_LANGUAGE];
    }else if ([languageKey isEqualToString:@"粤语"]) {
        [self.asrEventManager setParameter:@(EVoiceRecognitionLanguageCantonese) forKey:BDS_ASR_LANGUAGE];
    }else if ([languageKey isEqualToString:@"四川话"]) {
        [self.asrEventManager setParameter:@(EVoiceRecognitionLanguageSichuanDialect) forKey:BDS_ASR_LANGUAGE];
    }else if ([languageKey isEqualToString:@"英语"]) {
        [self.asrEventManager setParameter:@(EVoiceRecognitionLanguageEnglish) forKey:BDS_ASR_LANGUAGE];
    }
     self.languageKey=languageKey;
    DLog(@"setASRLanguage:%@", self.languageKey)
}
//EVoiceRecognitionLanguageChinese = 0,//中文普通话
//EVoiceRecognitionLanguageCantonese,//粤语
//EVoiceRecognitionLanguageEnglish,//英语
//EVoiceRecognitionLanguageSichuanDialect,//四川话

- (void)WakeupClientWorkStatus:(int)workStatus obj:(id)aObj
{
    switch (workStatus) {
        case EWakeupEngineWorkStatusStarted: {
            break;
        }
        case EWakeupEngineWorkStatusTriggered: {
            //唤醒成功
            [self wakeupOk:(NSString *)aObj];
            break;
        }
        case EWakeupEngineWorkStatusError: {
             DLog(@" WakeupEngineError:%@",(NSError *)aObj);
//            [self startWakeup];
            break;
        }
        default:
            break;
    }
}


-(void)wakeupOk:(NSString *)words{
      [self stopWakeup];
    BOOL b=[StorageUtil getNetStatus];
    NSLog(@"getNetStatus b=%d",b);
    if (YES) {
        self.synthesizerType=0;
//         [self synthesizerContent:@"你好，我在这里！"];
        [self handleResponse:CMD_HELLO];
    }else{
         self.synthesizerType=1;
         [self handleResponse:CMD_NO_NETWORK];
    }
}


-(void)delayPlayMusic{
    [self stopWakeup];
    [NSTimer scheduledTimerWithTimeInterval:0.10 target:self selector:@selector(playMusic) userInfo:nil repeats:NO];
}

/**
 * 播放音乐
 */
-(void)playMusic{
    NSLog(@"playMusic:%ld",(long)_playIndex);
    AVAudioPlayer *player=self.musicArray[_playIndex];
    player.volume=1.0;
//    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    
     [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategorySoloAmbient error:nil];
    BOOL b=[player prepareToPlay];
    if (b) {
        [player play];
    }
}

#pragma mark - 处理语音识别结果
- (void)handleRecogResult:(id)aObj {
    if (aObj) {
        NSString *result=aObj[@"results_recognition"][0];
        NSLog(@"识别结果：%@",result);
//        DLog(@"\n 转码识别结果：result2=%@",result);
//        BOOL b=self.notifyRecognitResult;
        if (YES) {
//           NSInteger  response=self.notifyRecognitResult(result);
            NSInteger  response=CMD_OK;
            self.synthesizerType=1;
           
//            [self synthesizerContent:respont];
        }
    }
}

/**
 * 处理回应
 */
-(void)handleResponse:(NSInteger)response{
      _playIndex=response-1;
//    switch (response) {
//        case CMD_OK:
//            _playIndex=1;
//            break;
//        case CMD_NO_FAMILY:
//            _playIndex=1;
//            break;
//        case CMD_NO_GROUP:
//            _playIndex=1;
//            break;
//        case CMD_SORRY:
//            _playIndex=1;
//            break;
//        default:
//            break;
//    }
    [self delayPlayMusic];
}



- (void)VoiceRecognitionClientWorkStatus:(int)workStatus obj:(id)aObj {
    switch (workStatus) {
            
        case EVoiceRecognitionClientWorkStatusStart: {// 检测到用户开始说话
            DLog(@"检测到用户开始说话");
            break;
        }
        case  EVoiceRecognitionClientWorkStatusStartWorkIng:// 识别工作开始，开始采集及处理数据
            DLog(@"识别工作开始，开始采集及处理数据");
            break;
            
        case  EVoiceRecognitionClientWorkStatusEnd: // 本地声音采集结束，等待识别结果返回      并结束录音
            DLog(@"采集结束，等待识别结果");
            break;
            
        case EVoiceRecognitionClientWorkStatusFinish: {//返回识别结果
//             DLog(@"返回识别结果");
                _isRecogniting=NO;
            [self handleRecogResult:aObj];
            break;
        }
        case  EVoiceRecognitionClientWorkStatusError: // 发生错误:
             DLog(@"识别出错：%@",aObj);
            self.synthesizerType=1;
//            [self synthesizerContent:@"对不起，我没听清，请再说一遍"];
//                _isRecogniting=NO;
            
            self.playIndex=CMD_SORRY;
            [self delayPlayMusic];
            break;
            
        case   EVoiceRecognitionClientWorkStatusLoaded: // 离线引擎加载完成
             DLog(@"离线引擎加载完成");
            break;
        case  EVoiceRecognitionClientWorkStatusUnLoaded: // 离线引擎卸载完成
             DLog(@"离线引擎卸载完成");
            break;
            
        case EVoiceRecognitionClientWorkStatusChunkEnd://
             DLog(@"CHUNK: 识别过程结束");
            [self handleResponse:CMD_OK];
            break;
        case EVoiceRecognitionClientWorkStatusRecorderEnd:
//             DLog(@"CHUNK: 录音机关闭");
            break;
        default:
//            ALog(@" Recognition workStatus=%d  aObj=%@ ",workStatus,aObj);
            break;
    }
}
- (NSDictionary *)parseLogToDic:(NSString *)logString
{
    NSArray *tmp = NULL;
    NSMutableDictionary *logDic = [[NSMutableDictionary alloc] initWithCapacity:3];
    NSArray *items = [logString componentsSeparatedByString:@"&"];
    for (NSString *item in items) {
        tmp = [item componentsSeparatedByString:@"="];
        if (tmp.count == 2) {
            [logDic setObject:tmp.lastObject forKey:tmp.firstObject];
        }
    }
    return logDic;
}

- (NSString *)getDescriptionForDic:(NSDictionary *)dic
{
    if (dic) {
        return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding];
    }
    return nil;
}


/*********************语音合成相关方法***********************/


#pragma mark - 开始合成语音
-(void)synthesizerContent:(NSString *)content{
    NSError* err = nil;
    [[BDSSpeechSynthesizer sharedInstance] speakSentence:content withError:&err];
    if (err) {
         DLog(@"\n 合成语音 err=%@",err);
    }
}

#pragma mark - 开始合成语音
-(void)cancelSynthesizer{
    [[BDSSpeechSynthesizer sharedInstance] cancel];
}
-(void)configureSDK{
     DLog(@"TTS version info: %@", [BDSSpeechSynthesizer version]);
    [BDSSpeechSynthesizer setLogLevel:BDS_PUBLIC_LOG_ERROR];
    [[BDSSpeechSynthesizer sharedInstance] setSynthesizerDelegate:self];
    [[BDSSpeechSynthesizer sharedInstance] setApiKey:API_KEY withSecretKey:SECRET_KEY];
    [[BDSSpeechSynthesizer sharedInstance] setSynthParam:@(NO) forKey:BDS_SYNTHESIZER_PARAM_ENABLE_AVSESSION_MGMT];
    [self configureOfflineTTS];
    
}

-(void)configureOnlineTTS{
    [[BDSSpeechSynthesizer sharedInstance] setSynthParam:@(BDS_SYNTHESIZER_SPEAKER_DYY) forKey:BDS_SYNTHESIZER_PARAM_SPEAKER];
    //    [[BDSSpeechSynthesizer sharedInstance] setSynthParam:@(10) forKey:BDS_SYNTHESIZER_PARAM_ONLINE_REQUEST_TIMEOUT];
}


-(void)configureOfflineTTS{
    NSError *err = nil;
    NSString* offlineEngineSpeechData = [[NSBundle mainBundle] pathForResource:@"Chinese_And_English_Speech_Female" ofType:@"dat"];
    NSString* offlineChineseAndEnglishTextData = [[NSBundle mainBundle] pathForResource:@"Chinese_And_English_Text" ofType:@"dat"];
    
    err = [[BDSSpeechSynthesizer sharedInstance] loadOfflineEngine:offlineChineseAndEnglishTextData speechDataPath:offlineEngineSpeechData licenseFilePath:nil withAppCode:APP_ID];
    if(err){
        DLog(@"OfflineTTS err:%@",err);
        return;
    }
}

- (void)synthesizerStartWorkingSentence:(NSInteger)SynthesizeSentence{
     DLog(@"开始合成的句子 %zi", SynthesizeSentence);
}

- (void)synthesizerFinishWorkingSentence:(NSInteger)SynthesizeSentence{
     DLog(@"完成合成的句子 %zi", SynthesizeSentence);
//    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(handleRecognition) userInfo:nil repeats:NO];
}

- (void)synthesizerSpeechStartSentence:(NSInteger)SpeakSentence{
     DLog(@"开始播放语音 %zi", SpeakSentence);
}

- (void)synthesizerSpeechEndSentence:(NSInteger)SpeakSentence{
    //NSLog(@"结束播放语音 %zi", SpeakSentence);
    [self cancelSynthesizer];
    [self handleRecognition];
}

-(void)handleRecognition
{
    NSError *error;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
    NSLog(@"\n 结束播放语音 开始识别语音 setCategory:%@",error);
    //    [self cancelSynthesizer];
    switch ( self.synthesizerType) {
        case 0:
            [self startOnlineRecognition];
            break;
        case 1:
            [self startWakeup];
            break;
        default:
            break;
    }
}



#pragma mark - audio代理
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player successfully:(BOOL)flag{
    ;
    NSLog(@" 播放结束时执行的动作 successfully=%d  isPlaying=%d",flag,player.isPlaying);
    //播放结束时执行的动作
    
//    [NSTimer scheduledTimerWithTimeInterval:0.050 target:self selector:@selector(handleRecognition) userInfo:nil repeats:NO];
    [self handleRecognition];
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer*)player error:(NSError *)error{
    NSLog(@"解码错误执行的动作:%@",error);
    //解码错误执行的动作
}
- (void)audioPlayerBeginInteruption:(AVAudioPlayer*) player{
     NSLog(@"处理播放中断的代码");
    //处理中断的代码
}
- (void)audioPlayerEndInteruption:(AVAudioPlayer*) player{
     NSLog(@"处理播放中断结束的代码");
    //处理中断结束的代码
}
@end
